﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Payment.Direct.Controllers
{
	public abstract class DirectPaymentController : ERPStore.Web.Controllers.CheckoutController
	{
		public DirectPaymentController(
			ERPStore.Services.ICartService cartService
			, ERPStore.Services.ISalesService salesService
			, ERPStore.Services.IAccountService accountService
			, ERPStore.Services.IEmailerService emailerService
			, ERPStore.Web.Services.IEmailTemplateService emailTemplateService
			, ERPStore.Services.IIncentiveService incentiveService
			, ERPStore.Services.CryptoService cryptoService
			, ERPStore.Services.IFraudService fraudService
			, ERPStore.Services.IOffersService offerService
			)
			: base(cartService, salesService, accountService, emailerService, emailTemplateService, incentiveService, cryptoService, offerService)
		{
			this.FraudService = fraudService;
		}

		protected ERPStore.Services.IFraudService FraudService { get; private set; }

		protected virtual string FinalizeViewName
		{
			get
			{
				return Web.Routing.ERPStoreRoutes.CHECKOUT_FINALIZED;
			}
		}

		protected virtual string PaymentName
		{
			get
			{
				return null;
			}
		}

		[ERPStore.Web.Controllers.ActionFilters.ZeroCacheActionFilter]
		[ERPStore.Web.Controllers.ActionFilters.TrackerActionFilter]
		public virtual ActionResult PaymentConfirmation()
		{
			var cart = CartService.GetCurrentCart(User);
			if (cart == null
				|| cart.ItemCount == 0)
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}

			var user = User.CurrentUser;

			if (user != null)
			{
				if (cart.DeliveryAddress == null
				|| cart.BillingAddress == null)
				{
					return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT);
				}
			}
			else
			{
				var registration = AccountService.GetRegistrationUser(User.VisitorId);
				if (registration == null)
				{
					return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT);
				}
				user = AccountService.CreateUserFromRegistration(registration);
				cart.BillingAddress = user.DefaultAddress;
				cart.DeliveryAddress = user.LastDeliveredAddress;
			}

			if (cart.PaymentModeName.IsNullOrTrimmedEmpty())
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT_PAYMENT);
			}

			var paymentList = SalesService.GetPaymentList(cart, User);
			var selectedPayment = paymentList.SingleOrDefault(i => i.Name.Equals(this.PaymentName, StringComparison.InvariantCultureIgnoreCase));

			if (selectedPayment == null)
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT_PAYMENT);
			}

			PrepareCart(cart);

			ViewData.Model = cart;
			var viewName = string.Format("~/views/checkout/{0}", selectedPayment.ConfirmationViewName);
			return View(viewName);
		}


		[AcceptVerbs(HttpVerbs.Post)]
		[global::ERPStore.Web.Controllers.ActionFilters.ZeroCacheActionFilter]
		[global::ERPStore.Web.Controllers.ActionFilters.TrackerActionFilter]
		public virtual ActionResult PaymentConfirmation(string condition)
		{
			string reason = null;
			if (FraudService.IsBlackListed(User.VisitorId, Request.UserHostAddress, out reason))
			{
				Logger.Warn(reason);
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}

			bool confirmation = (condition == "on");
			var cart = CartService.GetCurrentCart(User);

			if (cart == null
				|| cart.ItemCount == 0)
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}

			var user = User.CurrentUser;
			ERPStore.Models.RegistrationUser registration = null;

			if (user != null)
			{
				if (cart.DeliveryAddress == null
					|| cart.BillingAddress == null)
				{
					return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT);
				}
			}
			else
			{
				registration = AccountService.GetRegistrationUser(User.VisitorId);
				if (registration == null)
				{
					return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.CHECKOUT);
				}
				var registrationUser = AccountService.CreateUserFromRegistration(registration);
				cart.BillingAddress = registrationUser.DefaultAddress;
				cart.DeliveryAddress = registrationUser.LastDeliveredAddress;
			}

			// var brokenRules = SalesService.ValidateOrderCart(cart);
			// ModelState.AddModelErrors(brokenRules);

			bool result = TryValidateModel(cart);
			if (!result)
			{
				return RedirectToERPStoreRoute("Cart");
			}

			var paymentList = SalesService.GetPaymentList(cart, User);
			var selectedPayment = paymentList.SingleOrDefault(i => i.Name.Equals(PaymentName, StringComparison.InvariantCultureIgnoreCase));
			cart.PaymentModeName = selectedPayment.Name;
			ViewBag.PaymentList = paymentList;

			if (!confirmation)
			{
				ModelState.AddModelError("condition", "Vous devez accepter nos conditions de ventes pour pouvoir enregistrer cette commande");
			}

			// l'etape de la confirmation on recalcule les frais de port
			PrepareCart(cart);

			if (!ViewData.ModelState.IsValid)
			{
				ViewData.Model = cart;

				SalesService.ProcessExport(cart, User);
				CartService.ApplyProductStockInfoList(cart);
				string viewName = string.Format("~/views/checkout/{0}", selectedPayment.ConfirmationViewName);
				return View(viewName);
			}

			cart.AcceptCondition = true;

			ERPStore.Models.ISaleDocument order = null;

			bool isNewCustomer = false;
			string password = string.Empty;

			// l'etape de la confirmation on recalcule les frais de port
			if (user == null)
			{
				password = registration.Password;
				if (registration.IsSameBillingAddress)
				{
					registration.BillingAddressCity = registration.ShippingAddressCity;
					registration.BillingAddressCountryId = registration.ShippingAddressCountryId;
					registration.BillingAddressRecipientName = registration.ShippingAddressRecipientName;
					registration.BillingAddressRegion = registration.ShippingAddressRegion;
					registration.BillingAddressStreet = registration.ShippingAddressStreet;
					registration.BillingAddressZipCode = registration.ShippingAddressZipCode;
				}

				try
				{
					user = AccountService.RegisterUser(registration);
					Response.AddAuthenticatedCookie(user.Id, true);
					isNewCustomer = true;
				}
				catch (Exception ex)
				{
					LogError(Logger, ex);
					ModelState.AddModelError("_FORM", "Un problème technique empèche la creation de votre commande, veuillez reessayer ultérieurement");
				}

				// Affectation de l'adresse de livraison
				cart.DeliveryAddress = new ERPStore.Models.Address();
				cart.DeliveryAddress.City = registration.ShippingAddressCity;
				cart.DeliveryAddress.CountryId = registration.ShippingAddressCountryId;
				cart.DeliveryAddress.RecipientName = registration.ShippingAddressRecipientName;
				cart.DeliveryAddress.Region = registration.ShippingAddressRegion;
				cart.DeliveryAddress.Street = registration.ShippingAddressStreet;
				cart.DeliveryAddress.ZipCode = registration.ShippingAddressZipCode;

				// Affectation de l'adresse de facturation
				cart.BillingAddress = user.DefaultAddress;
				cart.CustomerId = user.Id;
			}

			try
			{
				// Traitement de l'export
				SalesService.ProcessExport(cart, User);

				// création de la commande
				order = SalesService.CreateOrderFromCart(user, cart, cart.PaymentModeName);
				using (var ts = TransactionHelper.GetNewReadCommitted())
				{
					cart.ConvertedEntityId = order.Id;
					CartService.Save(cart);
					ts.Complete();
				}
			}
			catch (Exception ex)
			{
				LogError(Logger, ex);
				ModelState.AddModelError("_FORM", "Un problème technique empèche la creation de votre commande, veuillez reessayer ultérieurement");
			}

			if (isNewCustomer)
			{
				AccountService.CloseRegistrationUser(User.VisitorId, user.Id);
			}

			if (!ModelState.IsValid)
			{
				ViewData.Model = cart;
				string viewName = string.Format("~/views/checkout/{0}", selectedPayment.ConfirmationViewName);
				return View(viewName);
			}

			// Préparation d'un paramètre encrypté
			var subject = new
			{
				OrderCode = order.Code,
				DocumentType = (order.Document == ERPStore.Models.SaleDocumentType.Order) ? "1" : "2",
				ExpirationDate = DateTime.Now.AddDays(1),
				IsNewCustomer = isNewCustomer,
				Password = password,
				CartCode = cart.Code,
			};
			var key = CryptoService.Encrypt(subject);

			return RedirectToERPStoreRoute(selectedPayment.FinalizedRouteName, new { key = key });
		}

		[Authorize(Roles = "customer")]
		[ERPStore.Web.Controllers.ActionFilters.ZeroCacheActionFilter]
		[ERPStore.Web.Controllers.ActionFilters.TrackerActionFilter]
		public virtual ActionResult Finalized(string key)
		{
			if (key.IsNullOrTrimmedEmpty())
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}
			ERPStore.Models.ISaleDocument order = null;
			var subject = new
			{
				Code = string.Empty,
				DocumentType = string.Empty,
				ExpirationDate = DateTime.MinValue,
				IsNewCustomer = false,
				Password = string.Empty,
				CartCode = string.Empty,
			};

			List<object> result = null;
			try
			{
				result = CryptoService.Decrypt(key, subject);
			}
			catch
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}
			var code = Convert.ToString(result[0]);
			var documentType = Convert.ToString(result[1]);
			var expirationDate = Convert.ToDateTime(result[2]);
			var isNewCustomer = Convert.ToBoolean(result[3]);
			var password = Convert.ToString(result[4]);
			var cartCode = Convert.ToString(result[5]);

			if (expirationDate < DateTime.Now)
			{
				// Tentative probable de hack
				Logger.Warn("Hack on order {0}", code);
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}

			if (documentType == "1")
			{
				order = SalesService.GetOrderByCode(code);
			}
			else
			{
				order = SalesService.GetQuoteByCode(code);
			}

			if (order == null)
			{
				return RedirectToERPStoreRoute(Web.Routing.ERPStoreRoutes.HOME);
			}

			try
			{
				if (!isNewCustomer)
				{
					password = string.Empty;
				}
				this.SendCustomerOrderConfirmation(order, password);
				this.SendAdminCustomerOrderConfirmation(order, cartCode, Request.UserHostAddress);
			}
			catch (Exception ex)
			{
				LogError(Logger, ex);
			}

			var paymentList = SalesService.GetPaymentList();
			var selectedPayment = paymentList.SingleOrDefault(i => i.Name.Equals(order.PaymentModeName, StringComparison.InvariantCultureIgnoreCase));

			ViewBag.CartCode = cartCode;
			ViewData.Model = order;
			var viewName = string.Format("~/views/checkout/{0}", selectedPayment.FinalizedViewName);
			return View(viewName);
		}

	}
}
